/*!
 **************************************************************
 *                                                            *  
 *   .=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-.       *  
 *    |                     ______                     |      *  
 *    |                  .-"      "-.                  |      *  
 *    |                 /            \                 |      *  
 *    |     _          |              |          _     |      *  
 *    |    ( \         |,  .-.  .-.  ,|         / )    |      *  
 *    |     > "=._     | )(__/  \__)( |     _.=" <     |      *  
 *    |    (_/"=._"=._ |/     /\     \| _.="_.="\_)    |      *  
 *    |           "=._"(_     ^^     _)"_.="           |      *  
 *    |               "=\__|IIIIII|__/="               |      *  
 *    |              _.="| \IIIIII/ |"=._              |      *  
 *    |    _     _.="_.="\          /"=._"=._     _    |      *  
 *    |   ( \_.="_.="     `--------`     "=._"=._/ )   |      *  
 *    |    > _.="                            "=._ <    |      *  
 *    |   (_/                                    \_)   |      *  
 *    |                                                |      *  
 *    '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-='      *  
 *                                                            *  
 *           LASCIATE OGNI SPERANZA, VOI CH'ENTRATE           *  
 **************************************************************   
 ******************************************************************
 *  项目名称 : proxy
 *  文件描述 :
 *  文件名称 : server.js
 *  版  本  : v1.0.0.0
 *  说  明  :  
 *  作  者  : night
 *  邮  箱  : 88962800@qq.com
 *  创建时间 : 2019:01-03 11:32 
 ******************************************************************
 Copyright © 2017-2019, All rights reserved.
 ******************************************************************
 */
import net from "net";
import uuid from "uuid/v4";
import {config} from "../config";
import Listener from './lib/listener';
import Buffer from './lib/buffer';
let server = {
    auth(data){
        if (config.auth) {
            return config.auth.uname == data.uname && config.auth.pwd == data.pwd;
        }
        return true;
    },
    validation(data){
        if (!this.auth(data)) {
            return false;
        }
        if (config.whiteList.length) {
            return false;
        }
        return true;
    },
    getConfig(){
    },
    clients: new Map(),
    listener: new Map(),
    map: new Map(),
    init(){
        this.signalServer = net.createServer((socket) => {
            let token = uuid();
            let timer;
            socket.on('data', async (buffer) => {
                let data = JSON.parse(buffer.toString());
                //console.log("recive data===>", data);
                if (!this.clients.has(token) &&!this.validation(data)) {
                    socket.end("author  error");
                    return;
                }
                if(this.clients.has(token)){
                    //console.log('time',data.time);
                    return;
                }
                this.clients.set(token, socket);
                this.addListener(token, data);
            });
            socket.on('close', () => {
                if(timer)clearInterval(timer);
                this.clients.delete(token);
                this.clearListener(token);

            });
            socket.on('error',(e)=>{
            });
            timer = setInterval(()=>{
                this.sendSignal(token,{time:new Date().getTime()});
            },5000);
        });
        this.signalServer.on('close',()=>{
            console.log("server close");
           for(let c in this.clients){
               this.sendSignal(c,{error:'server is closed'});
               this.clients.delete(c);
               this.clearListener(c);
           }
        });
        this.signalServer.listen(config.signalPort, () => {
            console.log("signalServer listen ", config.signalPort);
        });
        this.dataServer = net.createServer(async (socket) => {
            let context;
            let buffer = new Buffer();
            socket.on('data', (b) => {
                if (context)return;
                buffer.push(b);
            });
            let line = await buffer.readLine();
            if (!this.map.get(line)) {
                socket.destroy();
                return;
            }
            context = this.map.get(line);
            context.bind(socket);
        });
        this.dataServer.listen(() => {
            let add = this.dataServer.address();
            this.dataServer.port = add.port;
            console.log("dataServer listen ", add.port);
        })
    },
    sendSignal(token, data){
        if (!this.clients.has(token)) {
            return;
        }
        let wr = this.clients.get(token);
        let r = wr.write(`${JSON.stringify(data)}\n`)
       // console.log('write signal ==============>', r, JSON.stringify(data));
    },
    clearListener: function (token) {
        if (this.listener.get(token)) {
            for (let l of this.listener.get(token)) {
                l.close();
            }
            this.listener.delete(token);
        }
    },
    onListenerConnected(listener, context){
        if (!this.clients.get(listener.token)) {
            context.close();
            return;
        }
        this.map.set(context.key, context);
        context.on('close', () => {
            this.map.delete(context.key);
        });
        //this.sendSignal(listener.token, {port: listener.remote_port, remote_port: config.dataPort, token: context.key})
        this.sendSignal(listener.token, {port: listener.remote_port, remote_port:this.dataServer.port, token: context.key})
        //this.map.set(listener.token,context);
        // let server = net.createServer((socket)=>{
        //     context.bind(socket);
        //      socket.on('close',()=>{
        //          server.close();
        //      })
        // });
        // server.listen(()=>{
        //     this.sendSignal(token,{port:listener.remote_port,remote_port:server.address().port,token:listener.token});
        // });
    },
    addListener: function (id, data) {
        let ts = [];
        for (var d of data.tunnels) {
            try {
                let t = new Listener({token: id, port: d.remote_port, remote_port: d.port});
                t.on('connection', (listener, context) => {
                    this.onListenerConnected(listener, context)
                });
                ts.push(t);
            }
            catch (e) {
                this.sendSignal(id,{error:`server error:${e.message}`});
            }
        }
        this.listener.set(id, ts);
    }
}
server.init();
process.on('uncaughtException', function (err) {
    //打印出错误
    console.log("uncaughtException===>", err);
});